package main

import (
	"bytes"
	"database/sql"
	"encoding/json"
	"fmt"
	"os"
	"strings"

	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
)

//goland:noinspection SqlDialectInspection,SqlNoDataSourceInspection
const (
	QueryTableList = `SELECT DISTINCT TABLE_NAME, TABLE_COMMENT 
FROM information_schema.TABLES WHERE TABLE_SCHEMA = ?`

	QueryTableFieldList = `
SELECT COLUMN_NAME, COLUMN_DEFAULT, DATA_TYPE, COLUMN_COMMENT
	, IF(COLUMN_KEY = 'PRI', 'TRUE', 'FALSE') AS IS_KEY
	, NUMERIC_PRECISION, NUMERIC_SCALE, CHARACTER_MAXIMUM_LENGTH, IS_NULLABLE
	, UPPER(COLUMN_TYPE) AS COLUMN_TYPE
	, IF(EXTRA = 'auto_increment', 'TRUE', 'FALSE') AS IS_AUTO
FROM information_schema.COLUMNS WHERE TABLE_NAME = ? AND TABLE_SCHEMA = ?`
)

type table struct {
	TableName    string         `db:"TABLE_NAME"`
	TableComment sql.NullString `db:"TABLE_COMMENT"`
}

type field struct {
	ColumnName             string         `db:"COLUMN_NAME"`
	ColumnDefault          sql.NullString `db:"COLUMN_DEFAULT"`
	DataType               string         `db:"DATA_TYPE"`
	ColumnComment          string         `db:"COLUMN_COMMENT"`
	IsKey                  string         `db:"IS_KEY"`
	NumericPrecision       sql.NullInt64  `db:"NUMERIC_PRECISION"`
	NumericScale           sql.NullInt64  `db:"NUMERIC_SCALE"`
	CharacterMaximumLength sql.NullInt64  `db:"CHARACTER_MAXIMUM_LENGTH"`
	IsNullable             string         `db:"IS_NULLABLE"`
	ColumnType             string         `db:"COLUMN_TYPE"`
	IsAuto                 string         `db:"IS_AUTO"`
}

// 测试数据源连接
func testDBConn(config DBConfig) error {
	var dbUrl = config.DBUsername + ":" + config.DBPassword + "@tcp("
	if strings.Contains(config.DBHost, ":") {
		dbUrl += config.DBHost + ")/"
	} else {
		dbUrl += config.DBHost + ":3306)/"
	}
	dbUrl += config.DBName + "?charset=utf8&parseTime=True&loc=Local"
	if data, err := sqlx.Open("mysql", dbUrl); err != nil {
		return err
	} else {
		return data.Ping()
	}
}

// 获取待生成代码的表信息
func loadTables(config DBConfig) (error, []table) {
	var (
		tableMapList []table
		dbUrl        = config.DBUsername + ":" + config.DBPassword + "@tcp("
	)
	if strings.Contains(config.DBHost, ":") {
		dbUrl += config.DBHost + ")/"
	} else {
		dbUrl += config.DBHost + ":3306)/"
	}
	dbUrl += config.DBName + "?charset=utf8&parseTime=True&loc=Local"
	db, _ := sqlx.Open("mysql", dbUrl)
	defer func() {
		_ = db.Close()
	}()
	if err := db.Select(&tableMapList, QueryTableList, config.DBName); err != nil {
		return err, tableMapList
	}
	return nil, tableMapList
}

// 获取指定表的字段信息
func loadFields(tableName string, config DBConfig) []field {
	var dbUrl = config.DBUsername + ":" + config.DBPassword + "@tcp("
	if strings.Contains(config.DBHost, ":") {
		dbUrl += config.DBHost + ")/"
	} else {
		dbUrl += config.DBHost + ":3306)/"
	}
	dbUrl += config.DBName + "?charset=utf8&parseTime=True&loc=Local"
	db, _ := sqlx.Open("mysql", dbUrl)
	defer func() {
		_ = db.Close()
	}()
	var fieldList []field
	if err := db.Select(&fieldList, QueryTableFieldList, tableName, config.DBName); err != nil {
		fmt.Println(err)
		return fieldList
	}
	return fieldList
}

// 获取ID字段
func fieldId(fields []field) string {
	fieldId := ""
	for _, field := range fields {
		if strings.EqualFold(field.IsKey, "TRUE") {
			fieldId = field.ColumnName
		}
	}
	return fieldId
}

func fieldHasAuto(fields []field) bool {
	for _, field := range fields {
		if strings.EqualFold(field.IsAuto, "TRUE") {
			return true
		}
	}
	return false
}

func fileExists(path string) bool {
	_, err := os.Stat(path)
	if err != nil {
		if os.IsExist(err) {
			return true
		}
		if os.IsNotExist(err) {
			return false
		}
		return false
	}
	return true
}

func formatJson(str string) string {
	var out bytes.Buffer
	if err := json.Indent(&out, []byte(str), "", "    "); err != nil {
		return str
	}
	return out.String()
}
